/*!
 * Node module v1.0.0 of jRaiser javascript library
 * http://code.google.com/p/jraiser/
 *
 * Author: Heero.Luo
 * Licensed under MIT license
 *
 * Date: Tue Jun 05 2012 10:34:23 GMT+0800
 */
define(function(require, exports, module) { 'use strict';

var core = require('core/1.0.x/core'), Sizzle = require('sizzle/1.5.x/sizzle'),
	$base = require('node-base/1.0.x/node-base'),
	$data = require('node-data/1.0.x/node-data'),
	$attr = require('node-attr/1.0.x/node-attr'),
	$style = require('node-style/1.0.x/node-style'),
	$event = require('node-event/1.0.x/node-event'),
	$insertion = require('node-insertion/1.0.x/node-insertion'),
	$traversal = require('node-traversal/1.0.x/node-traversal'),
	domReady = require('domready/1.0.x/domready');


var isWindow = $base.isWindow, isNode = $base.isNode;
function querySelector(selector, context) {
	if ( context != null && context.length != null && !isNode(context) && !isWindow(context) ) {
		// 有多个context，逐个匹配selector
		var i = -1, len = context.length, ret = [ ];
		while (++i < len) {
			Sizzle(selector, context[i], ret);
		}
		if (len > 1) {
			// context多于一个的情况下，有可能出现重复元素
			Sizzle.uniqueSort(ret);
		}
		return ret;
	} else {
		return Sizzle(selector, context);
	}
}
function query(selector, context) {
	var ret;

	if (null == selector) {
		throw new Error('selector can not be null');
	} else if (typeof selector === 'string') {
		ret = querySelector(selector, context);
	} else if ( isNode(selector) || isWindow(selector) ) {
		ret = [selector];
	} else {
		ret = selector;
	}

	return ret;
}


var arrProto = Array.prototype;

/**
 * 节点集合类
 * @param {Array|ArrayLike} 节点数组或类数组
 * @param {Number} 数量限制
 */
var NodeList = core.newClass(function(elts) {
	var i = -1, len = elts ? elts.length : 0, self = this;
	while (++i < len) {
		if ( elts[i] ) { self[i] = elts[i]; }
	}
	self.length = len;
}, {
	/**
	 * 返回由指定节点
	 * @param {Number} 节点下标。如果为负数，则返回最后一个节点；如果未指定，则返回所有节点
	 * @return {DOMElement,Array<DOMElement>} 指定节点
	 */
	raw : function(i) {
		i = Number(i);
		return isNaN(i) ? arrProto.slice.call(this) :	(i < 0 ? this[this.length - 1] : this[i]);
	},
	
	/**
	 * 返回包含指定节点的NodeList集合
	 * @param {Number} 节点下标。如果为负数，则返回最后一个节点；如果未指定，则返回所有节点
	 * @return {NodeList} 包含指定节点的NodeList集合
	 */
	get : function() {
		return new this.constructor( this.raw.apply(this, arguments) );
	},
	
	/**
	 * 以当前节点为上下文，根据选择器匹配节点
	 * @param {String} 选择器
	 * @return {NodeList} 由匹配到的节点组成的NodeList集合
	 */
	find : function(selector) {
		return new this.constructor( querySelector(selector, this) );
	},
	
	/**
	 * 从当前节点集合中过滤出符合指定规则的节点
	 * @param {String|Function} 选择器或过滤函数
	 * @return {NodeList} 由过滤出的节点组成的新节点集合
	 */
	filter : function(selector) {
		return new this.constructor(
			typeof selector === 'function' ?
				arrProto.filter.apply(this, arguments) : Sizzle.matches(selector, this)
		);
	},
	
	/**
	 * 返回包含当前节点及匹配到的新节点的NodeList集合（重复节点将会被去除）
	 * 参数同node函数 (See line 165)
	 * @return {NodeList} 包含当前节点和新节点的集合
	 */
	add : function(selector, context) {
		return new this.constructor(
			Sizzle.uniqueSort(
				arrProto.concat.apply( this.raw(), query(selector, context) )
			)
		);
	},
	
	/**
	 * 对当前节点进行唯一性筛选并排序
	 * @return {NodeList} 当前节点集合
	 */
	uniqueSort : function() {
		Sizzle.uniqueSort(this);
		return this;
	},
	
	/**
	 * 对当前节点集合中的每个节点执行指定函数
	 * @param {Function} 操作函数，原型为callback(node, index, nodeList)
	 *   当函数返回值为false时，遍历中断
	 *   !!! 与jQuery不同，操作函数的第一个参数是值，第二个参数是下标
	 * @return {NodeList} 当前节点集合
	 */
	each : function(callback) { return core.each(this, callback); },
	
	/**
	 * 对当前节点集合中的每个节点执行指定函数
	 * 参数及返回值与Array.prototype.forEach一致
	 */
	forEach : arrProto.forEach,
	
	/**
	 * 对当前节点集合进行排序
	 * 参数及返回值与Array.prototype.sort一致
	 */
	sort : arrProto.sort
});


// 模块接口工厂
function nodeFactory(exts, SubNodeList) {
	SubNodeList = SubNodeList || NodeList;
	if (exts && exts.length) {
		SubNodeList = core.newClass(function() { }, null, SubNodeList);
		exts.unshift(SubNodeList.prototype);
		core.extend.apply(core, exts);
	}
	
	/**
	 * 根据选择器及上下文匹配节点
	 * @param {String} 选择器
	 * @param {DOMElement} 上下文
	 * @return {NodeList} 由匹配到的节点组成的NodeList对象
	 */
	/**
	 * 使用指定节点创建NodeList对象
	 * @param {DOMElement|Array<DOMElement>|ArrayLike<DOMElement>} 节点
	 * @return {NodeList} 以指定节点创建的NodeList对象
	 */
	var node = function(selector, context) {
		return new SubNodeList( query(selector, context) );
	};
	
	core.extend(node, {
		/**
		 * See line 59
		 */
		NodeList : SubNodeList,
		
		/**
		 * 生成一套包含扩展NodeList类的模块接口
		 * @param {Object*|Array} 若干个NodeList类的扩展方法
		 * @return {Object} 包含扩展NodeList类的模块接口
		 */
		plugin : function(exts) {
			return nodeFactory( core.toArray(core.isArray(exts) ? exts : arguments), this.NodeList );
		},

		/**
		 * 在DOMReady后执行操作
		 * @param {Function} 操作函数
		 */
		ready : domReady
	});
	
	return node;
}


// 接口输出（默认把常用的扩展加上）
module.exports = nodeFactory([
	$data.nodeApis, $attr.nodeApis,
	$style.nodeApis, $event.nodeApis,
	$insertion.nodeApis, $traversal.nodeApis
]);

});